package com.linsen.core.web.aspect;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import com.linsen.core.common.constant.LinsenConstant;
import com.linsen.core.common.exception.RequestBusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ValidationUtils;

import javax.validation.Valid;
import javax.validation.Validation;
import java.util.List;

/**
 * @author zhaoyong
 * @date 2023/3/21
 */
@Aspect
@Slf4j
@RequiredArgsConstructor
public class RequestValidAspect {
    @Pointcut("within(" + LinsenConstant.LINSEN_APP_PACKAGE + "..*) " + "&& (@annotation(org.springframework.web.bind.annotation.RequestMapping) " + "|| @annotation(org.springframework.web.bind.annotation.GetMapping) " + "|| @annotation(org.springframework.web.bind.annotation.PostMapping) " + "|| @annotation(org.springframework.web.bind.annotation.PutMapping) " + "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping))")
    public void pointcut() {

    }

    @Before("pointcut()")
    public void before(JoinPoint point) {
        Object[] args = point.getArgs();
        if (ArrayUtil.isEmpty(args)) {
            return;
        }

        BindingResult bindingResult = this.getBindingResult(point.getArgs());
        if (ObjUtil.isNull(bindingResult)) {
            return;
        }

        if (bindingResult.hasErrors()) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            throw new RequestBusinessException(fieldErrors.get(0).getDefaultMessage());
        }
    }

    private BindingResult getBindingResult(Object[] args) {
        for (Object arg : args) {
            if (arg instanceof BindingResult) {
                return (BindingResult) arg;
            }
        }

        return null;
    }
}
